查看原文
其他

.NET问答:如何理解 IEnumerable<T> 和 IQueryable<T>

DotNet 2021-09-23

The following article is from NET技术问答 Author overflow

咨询区

  • stackoverflowuser

请问类型 IQueryable<T>IEnumerable<T>  有什么异同?我应该使用哪一个而不是另一个,代码如下:

IQueryable<Customer> custs = from c in db.Customers  
where c.City == "<City>"  
select c;  
  
IEnumerable<Customer> custs = from c in db.Customers  
where c.City == "<City>"  
select c;  

我知道这两者都是延迟执行,我应该如何选择?

回答区

  • Kasper Roma

是的,两者都是延迟执行,我来用 SQL Server profiler 来演示两者的不同,考虑下面的代码:

MarketDevEntities db = new MarketDevEntities();  
  
IEnumerable<WebLog> first = db.WebLogs;  
var second = first.Where(c => c.DurationSeconds > 10);  
var third = second.Where(c => c.WebLogID > 100);  
var result = third.Where(c => c.EmailAddress.Length > 11);  
  
Console.Write(result.First().UserName);  

SQL Server profiler 中我捕获到了如下的sql。

"SELECT * FROM [dbo].[WebLog]" 

这张表中大概有 100w 条记录,sql花费了大概 90s, 显而易见,代码首先会将 WebLog,也 就是将所有的表记录全部灌入到内存中,然后依次使用 Where() 在内存中进行过滤。接下来用 IQueryable 替代 IEnumerable, 再次观察一下 SQL Server profiler,可以捕获如下sql。

"SELECT TOP 1 * FROM [dbo].[WebLog] WHERE [DurationSeconds] > 10 AND [WebLogID] > 100 AND LEN([EmailAddress]) > 11" 

这个 sql 大概花费了 4s。IQueryable 中有一个 Expression 属性,它存储着 表达式树,它的完整构建在于 result 变量处(这里是延迟执行),当真正执行的时候,这个 表达式树 会被解析成 sql 到数据库中执行。

点评区

Kasper Roma 大佬说的是有理有节,图文并茂,一看就懂,大写的🐂👃,我还真的特意看了下有没有 Expression 属性 😅😅😅

    //  
    // Summary:  
    //     Provides functionality to evaluate queries against a specific data source wherein  
    //     the type of the data is not specified.  
    public interface IQueryable : IEnumerable  
    {  
        //  
        // Summary:  
        //     Gets the type of the element(s) that are returned when the expression tree associated  
        //     with this instance of System.Linq.IQueryable is executed.  
        //  
        // Returns:  
        //     A System.Type that represents the type of the element(s) that are returned when  
        //     the expression tree associated with this object is executed.  
        Type ElementType { get; }  
        //  
        // Summary:  
        //     Gets the expression tree that is associated with the instance of System.Linq.IQueryable.  
        //  
        // Returns:  
        //     The System.Linq.Expressions.Expression that is associated with this instance  
        //     of System.Linq.IQueryable.  
        Expression Expression { get; }  
        //  
        // Summary:  
        //     Gets the query provider that is associated with this data source.  
        //  
        // Returns:  
        //     The System.Linq.IQueryProvider that is associated with this data source.  
        IQueryProvider Provider { get; }  
    }  


- EOF -

推荐阅读  点击标题可跳转

C#中使用 CancellationToken 处理异步任务

ASP.NET Core 限流控制:AspNetCoreRateLimit

如何在 C# 中使用 yield


看完本文有收获?请转发分享给更多人

推荐关注「DotNet」,提升.Net技能 

点赞和在看就是最大的支持❤️

: . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存